package com.leyou.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.auth.utils.UserContext;
import com.leyou.common.exceptions.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.trade.dto.OrderFormDTO;
import com.leyou.trade.entity.Order;
import com.leyou.trade.entity.OrderDetail;
import com.leyou.trade.entity.OrderLogistics;
import com.leyou.trade.entity.enums.OrderStatus;
import com.leyou.trade.mapper.OrderMapper;
import com.leyou.trade.service.OrderDetailService;
import com.leyou.trade.service.OrderLogisticsService;
import com.leyou.trade.service.OrderService;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ORDER_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.EVICT_ORDER_KEY;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private ItemClient itemClient;
    @Autowired
    private OrderDetailService detailService;
    @Autowired
    private UserClient userClient;
    @Autowired
    private OrderLogisticsService logisticsService;
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    @Transactional
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.新增订单表
        Order order = new Order();
        // 1.1.订单金额
        Map<Long, Integer> carts = orderFormDTO.getCarts();
        // 1.1.1.首先获取订单中包含的商品的id
        Set<Long> skuIds = carts.keySet();
        // 1.1.2.根据id查询sku
        List<SkuDTO> skuList = itemClient.querySkuByIds(skuIds);
        // 1.1.3.计算总金额
        long total = 0;
        for (SkuDTO sku : skuList) {
            Integer num = carts.get(sku.getId());
            total += sku.getPrice() * num;
        }
        order.setTotalFee(total);
        order.setPostFee(0L); // 目前是全场包邮
        order.setActualFee(order.getTotalFee());// 目前没有优惠，等于总金额
        // 1.2.用户id
        Long userId = UserContext.getUser().getId();
        order.setUserId(userId);
        // 1.3.订单状态
        order.setStatus(OrderStatus.INIT.getValue());
        // 1.4.支付方式
        order.setPaymentType(orderFormDTO.getPaymentType());
        // 1.5.写入数据库
        boolean success = save(order);
        if (!success) {
            throw new LyException(500, "新增订单失败！");
        }

        Long orderId = order.getOrderId();
        // 2.新增订单详情表, 根据sku信息，封装为OrderDetail信息
        // 2.1.创建OrderDetail的集合，封装数据
        List<OrderDetail> detailList = new ArrayList<>(skuList.size());
        // 2.2.遍历和封装
        for (SkuDTO sku : skuList) {
            // 2.3.封装
            OrderDetail detail = new OrderDetail();
            detail.setTitle(sku.getTitle());
            detail.setSpec(sku.getSpecialSpec());
            detail.setSkuId(sku.getId());
            detail.setPrice(sku.getPrice());
            detail.setOrderId(orderId);
            detail.setNum(carts.get(sku.getId()));
            detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            detailList.add(detail);
        }
        // 2.4.写入数据库
        detailService.saveBatch(detailList);

        // 3.新增订单物流表
        Long addressId = orderFormDTO.getAddressId();
        // 3.1.查询物流地址
        AddressDTO addressDTO = userClient.queryAddressById(addressId);
        // 3.2.把地址封装到OrderLogistics对象中
        OrderLogistics orderLogistics = addressDTO.toEntity(OrderLogistics.class);
        orderLogistics.setOrderId(orderId);
        // 3.3.写入数据库
        logisticsService.save(orderLogistics);

        // 4.扣减库存
        try {
            itemClient.deductStock(orderFormDTO.getCarts());
        } catch (FeignException e) {
            throw new LyException(e.status(), e.contentUTF8());
        }

        // TODO 5.清空购物车

        // 6.发送MQ延迟消息
        amqpTemplate.convertAndSend(ORDER_EXCHANGE_NAME, EVICT_ORDER_KEY, orderId);
        return orderId;
    }

    @Override
    public Integer queryOrderStatus(String id) {
        // 1.查询订单
        Order order = getById(id);
        if (order == null) {
            throw new LyException(400, "订单不存在！");
        }
        // 2.返回订单状态
        return order.getStatus();
    }

    @Override
    @Transactional
    public void evictOverdueOrder(Long orderId) {
        // 1.查询订单
        Order order = getById(orderId);
        if (order == null) {
            // 订单不存在，结束任务
            log.warn("要清理的订单不存在！订单id: {}", orderId);
            return;
        }
        // 2.判断订单状态
        if (!Objects.equals(order.getStatus(), OrderStatus.INIT.getValue())) {
            // 订单已支付，结束任务
            return;
        }
        // 3.订单未支付，需要关闭订单
        // update tb_order set status = 5, close_time = NOW() where id = x AND status = 1
        boolean success = update().set("status", OrderStatus.CLOSED.getValue())
                .set("close_time", new Date())
                .eq("order_id", orderId)
                .eq("status", OrderStatus.INIT.getValue())
                .update();
        if (!success) {
            // 订单已经处理完成，无需重复处理
            return;
        }
        // 4.恢复库存
        // 4.1.查询订单中包含的商品信息
        List<OrderDetail> detailList = detailService.query().eq("order_id", orderId).list();
        if (CollectionUtils.isEmpty(detailList)) {
            // 订单中没有商品，结束任务
            log.warn("订单中没有商品，订单信息有误。订单id：{}", orderId);
            return;
        }
        // 4.2.获取订单详情中的skuId和num形成一个map
        /*Map<Long, Integer> skuMap = new HashMap<>(detailList.size());
        for (OrderDetail detail : detailList) {
            skuMap.put(detail.getSkuId(), detail.getNum());
        }*/
        Map<Long, Integer> skuMap = detailList.stream()
                .collect(Collectors.toMap(OrderDetail::getSkuId, OrderDetail::getNum));
        // 4.3.恢复库存
        try {
            itemClient.plusStock(skuMap);
        } catch (FeignException e) {
            throw new LyException(e.status(), e.contentUTF8());
        }
    }
}